package com.os.opencv.java.chapter7;

import org.opencv.core.*;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import java.util.Random;

public class ConnectedComponentsWithStats {

    public static void main(String[] args) {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        //读取图像并在屏幕上显示
        Mat src = Imgcodecs.imread("/Users/matt/Pictures/xigua.jpg");
        HighGui.imshow("src", src);
        HighGui.waitKey(0);

        //将图像转换为灰度图并二值化
        Mat gray = new Mat();
        Imgproc.cvtColor(src, gray, Imgproc.COLOR_BGR2GRAY);
        Core.bitwise_not(gray, gray);
        Mat binary = new Mat();
        Imgproc.threshold(gray, binary, 0, 255, Imgproc.THRESH_BINARY | Imgproc.THRESH_OTSU);

        //在屏幕上显示二值图
        HighGui.imshow("binary", binary);
        HighGui.waitKey(0);

        //标记联通域
        Mat labels = new Mat(src.size(), CvType.CV_32S);
        Mat stats = new Mat();
        Mat centroids = new Mat();
        int num = Imgproc.connectedComponentsWithStats(binary, labels, stats, centroids);

        //定义颜色额数组，用于不同的联通区域
        Scalar[] colors = new Scalar[num];

        //随机生成颜色
        Random rd = new Random();
        for(int i=0; i<num; i++){
            int r = rd.nextInt(256);
            int g = rd.nextInt(256);
            int b = rd.nextInt(256);
            colors[i] = new Scalar(r, g, b);
        }

        //创建用于标记及绘图的图像dst
        Scalar white = new Scalar(255, 255, 255);
        Mat dst = new Mat(src.size(), src.type(), white);

        int width = src.cols();
        int height = src.rows();
        for(int i=0; i<height; i++){
            for(int j=0; j<width; j++){
                //获取标签号
                int label = (int)labels.get(i, j)[0];

                //将背景意外的联通区域改为黑色
                if(label != 0){
                    double[] val = new double[]{0,0,0};
                    dst.put(i, j, val);
                }
            }
        }

        //绘制哥哥联通区域的之心和外接矩形
        for(int i=1; i<num; i++){
            //获取联通区域中心位置
            double cx = centroids.get(i, 0)[0];
            double cy = centroids.get(i, 1)[0];

            int left = (int)stats.get(i, Imgproc.CC_STAT_LEFT)[0];
            int top = (int)stats.get(i, Imgproc.CC_STAT_TOP)[0];
            width = (int)stats.get(i, Imgproc.CC_STAT_LEFT)[0];
            height = (int)stats.get(i, Imgproc.CC_STAT_HEIGHT)[0];

            //绘制连通域质心
            Imgproc.circle(dst, new Point(cx, cy), 2, new Scalar(0,0,255), 2, 8, 0);

            //绘制连通域外接矩形
            Imgproc.rectangle(dst, new Point(left, top), new Point(left + width, top + height), colors[i], 2, 8, 0);

        }

        //在屏幕上显示最后结果
        HighGui.imshow("lebelled", dst);
        HighGui.waitKey(0);

        System.exit(0);

    }
}
